package edu.nwpu.zya.coreops.modules.alert.service.impl;

import com.alibaba.fastjson.JSONObject;
import edu.nwpu.zya.coreops.common.utils.Constant;
import edu.nwpu.zya.coreops.modules.alert.entity.*;
import edu.nwpu.zya.coreops.modules.alert.service.*;
import edu.nwpu.zya.coreops.modules.alert.vo.RuleVo;
import edu.nwpu.zya.coreops.modules.job.entity.JobRuleRelationEntity;
import edu.nwpu.zya.coreops.modules.job.entity.ScheduleJobEntity;
import edu.nwpu.zya.coreops.modules.job.service.JobRuleRelationService;
import edu.nwpu.zya.coreops.modules.job.service.ScheduleJobService;
import edu.nwpu.zya.coreops.modules.monitor.entity.MetricEntity;
import edu.nwpu.zya.coreops.modules.monitor.service.MetricService;
import edu.nwpu.zya.coreops.modules.resource.entity.AppEntity;
import edu.nwpu.zya.coreops.modules.resource.entity.EcsEntity;
import edu.nwpu.zya.coreops.modules.resource.entity.RdsEntity;
import edu.nwpu.zya.coreops.modules.resource.service.AppService;
import edu.nwpu.zya.coreops.modules.resource.service.EcsService;
import edu.nwpu.zya.coreops.modules.resource.service.RdsService;
import edu.nwpu.zya.coreops.modules.sys.entity.SysUserEntity;
import edu.nwpu.zya.coreops.modules.sys.service.SysUserService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import edu.nwpu.zya.coreops.common.utils.PageUtils;
import edu.nwpu.zya.coreops.common.utils.Query;

import edu.nwpu.zya.coreops.modules.alert.dao.RuleDao;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;


@Service("ruleService")
public class RuleServiceImpl extends ServiceImpl<RuleDao, RuleEntity> implements RuleService {
    @Autowired
    private RuleEcsRelationService ruleEcsRelationService;

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private DescriptionService descriptionService;

    @Autowired
    private MetricService metricService;

    @Autowired
    private EcsService ecsService;

    @Autowired
    private ScheduleJobService scheduleJobService;

    @Autowired
    private JobRuleRelationService jobRuleRelationService;

    @Autowired
    private RdsService rdsService;

    @Autowired
    private RuleRdsRelationService ruleRdsRelationService;

    @Autowired
    private AppService appService;

    @Autowired
    private RuleAppRelationService ruleAppRelationService;


    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<RuleEntity> page = this.page(
                new Query<RuleEntity>().getPage(params),
                new QueryWrapper<RuleEntity>()
        );

        return new PageUtils(page);
    }

    /**
     * 查询所有告警规则Vo
     * 'name'
     * 'level'
     * 'type'
     * 'status'
     * 'metricId'
     * 'instanceId'
     *
     * @param params
     * @return
     */
    @Override
    public PageUtils queryRuleVoPage(Map<String, Object> params) {
        Long userId = (Long) params.get("userId");

        QueryWrapper<RuleEntity> ruleEntityQueryWrapper = new QueryWrapper<>();

        //封装查询条件
        if (!StringUtils.isEmpty(params.get("name"))) {
            ruleEntityQueryWrapper.and(q->{
                q.like("name",params.get("name")).or().eq("id",params.get("name"));
            });
        }
        if (!StringUtils.isEmpty(params.get("level"))) {
            ruleEntityQueryWrapper.eq("level", Integer.parseInt((String) params.get("level")));
        }
        if (!StringUtils.isEmpty(params.get("type"))) {
            ruleEntityQueryWrapper.eq("type", Integer.parseInt((String) params.get("type")));
        }
        if (!StringUtils.isEmpty(params.get("status"))) {
            ruleEntityQueryWrapper.eq("status", Integer.parseInt((String) params.get("status")));
        }

        if (!(userId.longValue() == Constant.SUPER_ADMIN)) {
            ruleEntityQueryWrapper.eq("user_id", userId);
        }
        IPage<RuleEntity> page = this.page(
                new Query<RuleEntity>().getPage(params),
                ruleEntityQueryWrapper
        );
        PageUtils pageUtils = new PageUtils(page);
        if (page.getRecords().size() > 0) {
            List<RuleVo> ruleVos = page.getRecords().stream().map(item -> {
                RuleVo ruleVo = new RuleVo();
                // 查规则描述
                DescriptionEntity descriptionEntity = descriptionService.getOne(new QueryWrapper<DescriptionEntity>().eq("rule_id", item.getId()));
                BeanUtils.copyProperties(descriptionEntity, ruleVo);

                // 查规则基本信息
                BeanUtils.copyProperties(item, ruleVo);

                // 查指标名称
                MetricEntity metricEntity = metricService.getById(descriptionEntity.getMetricId());
                ruleVo.setMetricName(metricEntity.getName());
                ruleVo.setMetricUnit(metricEntity.getUnit());
                String metricName = metricEntity.getName();
                String description = "\"" + metricName + "\"超过" + descriptionEntity.getPeriod() + "个周期的";

                Integer aggType = descriptionEntity.getAggType();
                if (aggType == Constant.AggType.AVG.getValue()) {
                    description += Constant.AggType.AVG.getMsg();
                } else if (aggType == Constant.AggType.MIN.getValue()) {
                    description += Constant.AggType.MIN.getMsg();
                } else {
                    description += Constant.AggType.MAX.getMsg();
                }
                description += descriptionEntity.getCompareType();
                description += descriptionEntity.getThreshold();
                description += "(" + metricEntity.getUnit() + ")";

                ruleVo.setDescription(description);
                // 查用户名称
                ruleVo.setUserId(userId);
                SysUserEntity sysUserEntity = sysUserService.getById(userId);
                ruleVo.setUsername(sysUserEntity.getUsername());
                // 查实例id
                String instanceId = getInstanceIdByTypeAndRuleId(item.getType(), item.getId());
                ruleVo.setInstanceId(instanceId);
                return ruleVo;
            }).collect(Collectors.toList());
            // 根据参数筛选

            if (!StringUtils.isEmpty(params.get("metricId"))) {
                ruleVos = ruleVos.stream().filter(item -> {
                    return item.getMetricId().equals(Long.parseLong((String) params.get("metricId")));
                }).collect(Collectors.toList());
            }
            if (!StringUtils.isEmpty(params.get("instanceId"))) {
                ruleVos = ruleVos.stream().filter(item -> {
                    return item.getInstanceId().equals(params.get("instanceId"));
                }).collect(Collectors.toList());
            }

            pageUtils.setList(ruleVos);
        }

        return pageUtils;
    }


    /**
     * 根据id查询告警规则Vo，用于修改时回显
     *
     * @param id
     * @return
     */
    @Override
    public RuleVo getRuleVoById(Long id) {
        RuleVo ruleVo = new RuleVo();
        RuleEntity ruleEntity = this.getOne(new QueryWrapper<RuleEntity>().eq("id", id));
        BeanUtils.copyProperties(ruleEntity, ruleVo);

        String instanceId = getInstanceIdByTypeAndRuleId(ruleEntity.getType(), ruleEntity.getId());
        ruleVo.setInstanceId(instanceId);

        DescriptionEntity descriptionEntity = descriptionService.getOne(new QueryWrapper<DescriptionEntity>().eq("rule_id", ruleEntity.getId()));
        BeanUtils.copyProperties(descriptionEntity, ruleVo);

        MetricEntity metricEntity = metricService.getById(descriptionEntity.getMetricId());
        ruleVo.setMetricName(metricEntity.getName());
        ruleVo.setMetricUnit(metricEntity.getUnit());

        SysUserEntity userEntity = sysUserService.getById(ruleEntity.getUserId());
        ruleVo.setUserId(userEntity.getUserId());
        ruleVo.setUsername(userEntity.getUsername());

        return ruleVo;
    }

    /**
     * 保存告警规则Vo
     *
     * @param ruleVo
     */
    @Transactional
    @Override
    public void saveRuleVo(RuleVo ruleVo) {
        // 当前ruleVo没有id值
        RuleEntity ruleEntity = new RuleEntity();
        BeanUtils.copyProperties(ruleVo, ruleEntity);
        this.save(ruleEntity);

        DescriptionEntity descriptionEntity = new DescriptionEntity();
        BeanUtils.copyProperties(ruleVo, descriptionEntity);
        // 获得自增id
        descriptionEntity.setRuleId(ruleEntity.getId());
        descriptionService.save(descriptionEntity);
        // 根据实例类型存储告警关系
        saveRuleInstanceRelationByType(ruleEntity.getId(), ruleVo.getType(), ruleVo.getInstanceId());

        ruleVo.setId(ruleEntity.getId());
        MetricEntity metricEntity = metricService.getById(descriptionEntity.getMetricId());
        ruleVo.setMetricName(metricEntity.getName());

        // 开启定时任务
        startAlertTask(ruleVo);
    }

    /**
     * 开启定时任务来监控告警
     */
    private void startAlertTask(RuleVo ruleVo) {
        String params = JSONObject.toJSONString(ruleVo);
        ScheduleJobEntity jobEntity = new ScheduleJobEntity();
        jobEntity.setParams(params);
        jobEntity.setCronExpression("0 0/1 * * * ?");
        jobEntity.setBeanName("alertTask");
        jobEntity.setStatus(Constant.ScheduleStatus.NORMAL.getValue());
        scheduleJobService.saveJob(jobEntity);
        // 插入关系
        JobRuleRelationEntity relationEntity = new JobRuleRelationEntity();
        relationEntity.setJobId(jobEntity.getJobId());
        relationEntity.setRuleId(ruleVo.getId());
        jobRuleRelationService.save(relationEntity);
    }


    /**
     * 修改告警规则Vo
     *
     * @param ruleVo
     */
    @Transactional
    @Override
    public void updateByRuleVo(RuleVo ruleVo) {
        // 当前有ruleId值
        RuleEntity ruleEntity = new RuleEntity();
        BeanUtils.copyProperties(ruleVo, ruleEntity);
        this.updateById(ruleEntity);

        DescriptionEntity descriptionEntity = new DescriptionEntity();
        BeanUtils.copyProperties(ruleVo, descriptionEntity);
        descriptionEntity.setId(descriptionService.getOne(new QueryWrapper<DescriptionEntity>().eq("rule_id", ruleEntity.getId())).getId());
        // 获得自增id
        descriptionEntity.setRuleId(ruleEntity.getId());
        descriptionService.updateById(descriptionEntity);

        // 根据实例类型更新告警关系
        updateRuleInstanceRelationByType(ruleEntity.getId(), ruleVo.getType(), ruleVo.getInstanceId());


        MetricEntity metricEntity = metricService.getById(descriptionEntity.getMetricId());
        ruleVo.setMetricName(metricEntity.getName());
        // 更新定时任务状态
        updateAlertTask(ruleVo);
    }

    /**
     * 修改定时任务状态
     */
    private void updateAlertTask(RuleVo ruleVo) {
        JobRuleRelationEntity relationEntity = jobRuleRelationService.getOne(new QueryWrapper<JobRuleRelationEntity>().eq("rule_id", ruleVo.getId()));
        ScheduleJobEntity scheduleJobEntity = scheduleJobService.getById(relationEntity.getJobId());

        if (ruleVo.getStatus() == Constant.AlertStatus.DISABLED.getValue()) {
            scheduleJobEntity.setStatus(Constant.ScheduleStatus.PAUSE.getValue());
        }else {
            scheduleJobEntity.setStatus(Constant.ScheduleStatus.NORMAL.getValue());
        }
        scheduleJobEntity.setParams(JSONObject.toJSONString(ruleVo));

        scheduleJobService.update(scheduleJobEntity);
    }

    @Transactional
    @Override
    public void removeVoByRuleVos(List<RuleVo> ruleVos) {
        ruleVos.stream().forEach(ruleVo -> {
            // 级联删除告警描述和告警历史
            this.removeById(ruleVo.getId());
            // 删除告警规则和实例的关系
            deleteRuleInstanceRelationByType(ruleVo.getId(), ruleVo.getType());
        });

        // 删除定时任务
        deleteAlertTask(ruleVos.stream().map(item -> {
            return item.getId();
        }).collect(Collectors.toList()));
    }

    @Override
    public void deleteAlertTask(List<Long> ruleIds) {
        List<JobRuleRelationEntity> relationEntities = jobRuleRelationService.list(new QueryWrapper<JobRuleRelationEntity>().in("rule_id", ruleIds));
        List<Long> jobIds = relationEntities.stream().map(item -> {
            return item.getJobId();
        }).collect(Collectors.toList());

        jobRuleRelationService.removeByIds(relationEntities.stream().map(item->{
            return item.getId();
        }).collect(Collectors.toList()));

        scheduleJobService.deleteBatch(jobIds.toArray(new Long[0]));
    }

    @Override
    public List<RuleEntity> getRulesByTypeAndInstance(Integer type, String instanceId) {
        List<RuleEntity> ruleEntities = new ArrayList<>();
        if(type==Constant.InstanceType.ECS.getValue()){
            EcsEntity ecsEntity = ecsService.getEcsByInstanceId(instanceId);
            List<Long> ruleIds = ruleEcsRelationService.list(new QueryWrapper<RuleEcsRelationEntity>().eq("host_id", ecsEntity.getId())).stream().map(item -> {
                return item.getRuleId();
            }).collect(Collectors.toList());

            ruleEntities = this.listByIds(ruleIds);

        }else if(type==Constant.InstanceType.RDS.getValue()){
            // 如果类型为RDS
            RdsEntity rdsEntity=rdsService.getRdsByInstanceId(instanceId);

            List<Long> ruleIds = ruleRdsRelationService.list(new QueryWrapper<RuleRdsRelationEntity>().eq("rds_id", rdsEntity.getId())).stream().map(item -> {
                return item.getRuleId();
            }).collect(Collectors.toList());
            ruleEntities = this.listByIds(ruleIds);
        }else {
            // 如果类型为APP
            AppEntity appEntity= appService.getAppByInstanceId(instanceId);

            List<Long> ruleIds = ruleAppRelationService.list(new QueryWrapper<RuleAppRelationEntity>().eq("app_id", appEntity.getId())).stream().map(item -> {
                return item.getRuleId();
            }).collect(Collectors.toList());
            ruleEntities=this.listByIds(ruleIds);
        }

        return ruleEntities;
    }

    /**
     * 根据实例类型来删除 告警规则和实例关系表
     *
     * @param ruleId
     * @param type
     */
    private void deleteRuleInstanceRelationByType(Long ruleId, Integer type) {
        if (type == Constant.InstanceType.ECS.getValue()) {
            ruleEcsRelationService.remove(new QueryWrapper<RuleEcsRelationEntity>().eq("rule_id", ruleId));
        } else if (type == Constant.InstanceType.RDS.getValue()) {
            // 如果类型为RDS
            ruleRdsRelationService.remove(new QueryWrapper<RuleRdsRelationEntity>().eq("rule_id",ruleId));
        } else {
            // 如果类型为APP
            ruleAppRelationService.remove(new QueryWrapper<RuleAppRelationEntity>().eq("rule_id",ruleId));
        }
    }

    /**
     * 根据实例类型来更新 告警规则和实例的关系表
     *
     * @param ruleId
     * @param type
     * @param instanceId
     */
    private void updateRuleInstanceRelationByType(Long ruleId, Integer type, String instanceId) {
        if (type == Constant.InstanceType.ECS.getValue()) {
            EcsEntity ecsEntity = ecsService.getEcsByInstanceId(instanceId);
            RuleEcsRelationEntity ruleEcsRelationEntity = new RuleEcsRelationEntity();
            ruleEcsRelationEntity.setHostId(ecsEntity.getId());
            ruleEcsRelationEntity.setRuleId(ruleId);
            Long relationId = ruleEcsRelationService.getOne(new QueryWrapper<RuleEcsRelationEntity>().eq("rule_id", ruleId)).getId();
            ruleEcsRelationEntity.setId(relationId);

            ruleEcsRelationService.updateById(ruleEcsRelationEntity);
        } else if (type == Constant.InstanceType.RDS.getValue()) {
            // 如果类型为RDS
            RdsEntity rdsEntity= rdsService.getRdsByInstanceId(instanceId);
            RuleRdsRelationEntity ruleRdsRelationEntity=new RuleRdsRelationEntity();
            ruleRdsRelationEntity.setRdsId(rdsEntity.getId());
            ruleRdsRelationEntity.setRuleId(ruleId);
            Long relationId=ruleRdsRelationService.getOne(new QueryWrapper<RuleRdsRelationEntity>().eq("rule_id",ruleId)).getId();
            ruleRdsRelationEntity.setId(relationId);

            ruleRdsRelationService.updateById(ruleRdsRelationEntity);

        } else {
            // 如果类型为APP
            AppEntity appEntity = appService.getAppByInstanceId(instanceId);
            RuleAppRelationEntity ruleAppRelationEntity = new RuleAppRelationEntity();
            ruleAppRelationEntity.setAppId(appEntity.getId());
            ruleAppRelationEntity.setRuleId(ruleId);
            Long relationId = ruleAppRelationService.getOne(new QueryWrapper<RuleAppRelationEntity>().eq("rule_id", ruleId)).getId();

            ruleAppRelationEntity.setId(relationId);
            ruleAppRelationService.updateById(ruleAppRelationEntity);
        }
    }

    /**
     * 根据实例类型存储告警关系
     *
     * @param type       实例类型
     * @param instanceId 实例id
     */
    private void saveRuleInstanceRelationByType(Long ruleId, Integer type, String instanceId) {
        if (type == Constant.InstanceType.ECS.getValue()) {
            EcsEntity ecsEntity = ecsService.getEcsByInstanceId(instanceId);
            RuleEcsRelationEntity ruleEcsRelationEntity = new RuleEcsRelationEntity();
            ruleEcsRelationEntity.setHostId(ecsEntity.getId());
            ruleEcsRelationEntity.setRuleId(ruleId);

            ruleEcsRelationService.save(ruleEcsRelationEntity);
        } else if (type == Constant.InstanceType.RDS.getValue()) {
            // 如果类型为RDS
            RdsEntity rdsEntity = rdsService.getRdsByInstanceId(instanceId);
            RuleRdsRelationEntity ruleRdsRelationEntity = new RuleRdsRelationEntity();
            ruleRdsRelationEntity.setRdsId(rdsEntity.getId());
            ruleRdsRelationEntity.setRuleId(ruleId);

            ruleRdsRelationService.save(ruleRdsRelationEntity);
        } else {
            // 如果类型为APP
            AppEntity appEntity = appService.getAppByInstanceId(instanceId);

            RuleAppRelationEntity ruleAppRelationEntity = new RuleAppRelationEntity();
            ruleAppRelationEntity.setAppId(appEntity.getId());
            ruleAppRelationEntity.setRuleId(ruleId);

            ruleAppRelationService.save(ruleAppRelationEntity);
        }
    }

    /**
     * 根据实例类型，获得能关联告警的实例
     *
     * @param type
     * @param userId
     * @return
     */
    @Override
    public List<String> getRelatedInstancesByType(Integer type, Long userId) {
        List<String> instanceIds = getRelatedInstanceIdsByType(type, userId);
        return instanceIds;
    }

    /**
     * 根据实例类型和id，获得能该实例监控的指标
     *
     * @param instanceId
     * @param type
     * @return
     */
    @Override
    public List<MetricEntity> getMetricsByInstanceAndType(String instanceId, Integer type) {
        List<MetricEntity> metricEntities = getMetricsByInstanceIdAndType(instanceId, type);
        return metricEntities;
    }


    /**
     * 根据实例id和实例类型获取对应的监控指标
     *
     * @param instanceId 实例id
     * @param type       实例类型
     * @return
     */
    private List<MetricEntity> getMetricsByInstanceIdAndType(String instanceId, Integer type) {
        List<MetricEntity> metricEntities = new ArrayList<>();

        if (type == Constant.InstanceType.ECS.getValue()) {
            metricEntities = metricService.getEcsMetricsByInstanceId(instanceId);
        } else if (type == Constant.InstanceType.RDS.getValue()) {
            // 如果类型为RDS
            metricEntities = metricService.getRdsMetricsByInstanceId(instanceId);
        } else {
            // 如果类型为APP
            metricEntities = metricService.getAppMetricsByInstanceId(instanceId);
        }
        return metricEntities;
    }

    /**
     * 根据产品类型获取实例id
     *
     * @param type   产品类型
     * @param ruleId 告警规则id
     * @return
     */
    private String getInstanceIdByTypeAndRuleId(Integer type, Long ruleId) {
        String instanceId = null;
        if (type == Constant.InstanceType.ECS.getValue()) {
            // 如果类型为ECS
            EcsEntity ecsEntity = ecsService.getEcsByRuleId(ruleId);
            instanceId = ecsEntity.getEcsId();
        } else if (type == Constant.InstanceType.RDS.getValue()) {
            // 如果类型为RDS
            RdsEntity rdsEntity = rdsService.getRdsByRuleId(ruleId);
            instanceId = rdsEntity.getInstanceId();
        } else {
            // 如果类型为APP
            AppEntity appEntity = appService.getAppByRuleId(ruleId);
            instanceId = appEntity.getInstanceId();
        }

        return instanceId;
    }

    private List<String> getRelatedInstanceIdsByType(Integer productType, Long userId) {
        List<String> instanceIds = new ArrayList<String>();
        if (productType == Constant.InstanceType.ECS.getValue()) {
            // 如果类型为ECS
            if (!userId.equals(Constant.SUPER_ADMIN)) {
                List<EcsEntity> ecsEntities = ecsService.getEcsListByUserId(userId);
                instanceIds = ecsEntities.stream().map(ecs -> {
                    return ecs.getEcsId();
                }).collect(Collectors.toList());
            } else {
                // 如果是超级管理员则直接关联所有
                instanceIds = ecsService.list(new QueryWrapper<EcsEntity>().eq("status",1)).stream().map(item -> {
                    return item.getEcsId();
                }).collect(Collectors.toList());
            }

        } else if (productType == Constant.InstanceType.RDS.getValue()) {
            // 如果类型为RDS
            if (!userId.equals(Constant.SUPER_ADMIN)) {
                List<RdsEntity> rdsEntities=rdsService.getRdsListByUserId(userId);
                instanceIds=rdsEntities.stream().map(item->{
                    return item.getInstanceId();
                }).collect(Collectors.toList());
            } else {
                // 如果是超级管理员则直接关联所有
                instanceIds = rdsService.list(new QueryWrapper<RdsEntity>().eq("status",1)).stream().map(item -> {
                    return item.getInstanceId();
                }).collect(Collectors.toList());
            }
        } else {
            // 如果类型为APP
            if (!userId.equals(Constant.SUPER_ADMIN)) {
                List<AppEntity> appEntities=appService.getAppListByUserId(userId);
                instanceIds=appEntities.stream().map(item->{
                    return item.getInstanceId();
                }).collect(Collectors.toList());
            } else {
                // 如果是超级管理员则直接关联所有
                instanceIds = appService.list(new QueryWrapper<AppEntity>().eq("status",1)).stream().map(item -> {
                    return item.getInstanceId();
                }).collect(Collectors.toList());
            }
        }
        return instanceIds;
    }

}